

from CQutils import EPositionStatus, EQueueStatus
from google.appengine.api import memcache
import dal
import DSHelper
import datetime
import math
import models

def queue_stats_key(queue_cqid):
    return 'queue?%s:stats' % (queue_cqid)

def queue_avg_time_key(queue_cqid):
    return 'queue?%s:avgtime' % (queue_cqid)
    
def queue_last_service_time(queue_cqid):
    return 'queue?%s:last_service_time' % (queue_cqid)

def _get_last_service_time(queue_cqid):
    queue_invalidation_id = memcache.Client().get(dal.queue_invalidation_key(queue_cqid))
    if queue_invalidation_id == memcache.Client().get(dal.pos_invalidation_key(queue_cqid, "QUEUE_LAST_SERVICE")): 
        time = memcache.Client().get(queue_last_service_time(queue_cqid))
        if time is not None:
            return time
    memcache.Client().set(dal.pos_invalidation_key(queue_cqid, "QUEUE_LAST_SERVICE"), queue_invalidation_id)
    inservice_users = dal.get_inservice_users(queue_cqid)
    if len(inservice_users) == 0:
        return datetime.datetime.now() + 1
    last_user_cqid = inservice_users[0][0]
    pos = DSHelper.get_position_from_posid(dal.get_user_pos_in_queue(last_user_cqid, queue_cqid))
    time = pos.processed_time
    memcache.Client().set(queue_last_service_time(queue_cqid), time)
    return time
    
def _get_inqueue_detla_times(queue_cqid):
    queue_invalidation_id = memcache.Client().get(dal.queue_invalidation_key(queue_cqid))
    if queue_invalidation_id == memcache.Client().get(dal.pos_invalidation_key(queue_cqid, "QUEUE_DELTAS")):
        inqueue_deltas = memcache.Client().get(queue_stats_key(queue_cqid))
        if inqueue_deltas is not None:
            return inqueue_deltas
    memcache.Client().set(dal.pos_invalidation_key(queue_cqid, "QUEUE_DELTAS"), queue_invalidation_id)
    inqueue_deltas = []
    queue = DSHelper.get_queue_by_cqid(queue_cqid)
    if queue is None:
        return [0]
    positions = models.DSPosition.all().ancestor(queue).filter("status =", EPositionStatus.POST_PROCESS).order("join_time").fetch(100)
    for i in range(1, len(positions)):
        inqueue_deltas.append((positions[i].processed_time - positions[i - 1].processed_time).total_seconds())
    memcache.Client().set(queue_stats_key(queue_cqid), inqueue_deltas)
    return inqueue_deltas

def _get_simple_avg_turn_time(queue_cqid):
    queue_invalidation_id = memcache.Client().get(dal.queue_invalidation_key(queue_cqid))
    if queue_invalidation_id == memcache.Client().get(dal.pos_invalidation_key(queue_cqid, "QUEUE_AVG_TIME")):
        avg_time = memcache.Client().get(queue_avg_time_key(queue_cqid))
        if avg_time is not None:
            return avg_time
    memcache.Client().set(dal.pos_invalidation_key(queue_cqid, "QUEUE_AVG_TIME"), queue_invalidation_id)
    queue = DSHelper.get_queue_by_cqid(queue_cqid)
    if queue is None:
        return 0
    firstPos = models.DSPosition.all().ancestor(queue).filter("status =", EPositionStatus.POST_PROCESS).order("join_time").get()
    lastPos = models.DSPosition.all().ancestor(queue).filter("status =", EPositionStatus.POST_PROCESS).order("-join_time").get()
    if lastPos == None or firstPos == None:
        avg_time = 0
    else:
        queue_size = models.DSPosition.all().ancestor(queue).filter("status =", EPositionStatus.POST_PROCESS).count()
        avg_time = (lastPos.processed_time - firstPos.processed_time).total_seconds() / queue_size
    memcache.Client().set(queue_avg_time_key(queue_cqid), avg_time)
    return avg_time
    
def _advance_current_user(queue, ext):
    prev_user_query = models.DSPosition.all().ancestor(queue).filter("status =", EPositionStatus.IN_PROCESS).order("-join_time")
    if ext is not None:
        prev_user_query = prev_user_query.filter("ext", ext)
    prev_user = prev_user_query.get()
    if prev_user is not None:
        prev_user.status = EPositionStatus.POST_PROCESS
        prev_user.put() 
    queue.place = queue.place + 1
    queue.put()   
 
def _remove_outliers(turn_deltas, threshold = 0):
    if threshold is not 0:
        return [turn_time for turn_time in turn_deltas if abs(turn_time - threshold) <  (threshold/2)  ]
    return turn_deltas

def _calculate_turn_avarage(turn_deltas, threshold = 0):
    avg = 0
    margin = int(math.floor(len(turn_deltas) / 4))
    if margin != 0:      
        usfull_deltas = sorted(turn_deltas)[margin:-margin]
    else:
        usfull_deltas = turn_deltas
    if  len(usfull_deltas) is not 0:
        avg = sum(usfull_deltas) /  len(usfull_deltas)  
    if threshold is not 0:
        avg = max(avg, threshold * 0.5)
        avg = min(avg, threshold * 2)
    return avg

     

